﻿using System;
using System.Text;
using System.Text.RegularExpressions;

namespace UI.Common.Lipsum
{
    /// <summary>
    /// Represents a utility that generates Lipsum from a source.
    /// </summary>
    public class LipsumGenerator
    {
        public static string LipsumDefaultText = Properties.Resources.LoremIpsum;

        private static StringBuilder _lipsumText = null;
        private static string[] _preparedWords = new string[] { };

        public static string GenerateHtml(int count)
        {
            return Generate(count, FormatStrings.Paragraph.Html);
        }

        public static string Generate(int count)
        {
            return Generate(count, FormatStrings.Paragraph.LineBreaks);
        }

        public static string Generate(int count, string formatString)
        {
            return Generate(count, LipsumType.Paragraphs, formatString);
        }

        public static string Generate(int count, LipsumType feature, string formatString)
        {
            return GenerateLipsum(count, feature, formatString);
        }

        private static string GenerateLipsum(int count, LipsumType part, string formatString)
        {
            StringBuilder results = new StringBuilder();
            string[] data = new string[] { };
            if (part == LipsumType.Paragraphs)
            {
                data = GenerateParagraphs(count, formatString);
            }
            else if (part == LipsumType.Sentences)
            {
                data = GenerateSentences(count, formatString);
            }
            else if (part == LipsumType.Words)
            {
                data = GenerateWords(count);
            }
            else if (part == LipsumType.Characters)
            {
                data = GenerateCharacters(count);
            }
            else
            {
                throw new NotImplementedException("Sorry, this is not yet implemented.");
            }

            int length = data.Length;
            for (int i = 0; i < length; i++)
            {
                results.Append(data[i]);
            }

            return results.ToString();
        }

        private static string[] GenerateCharacters(int count)
        {
            string[] result = new string[1];

            /* This whole method needs some thought.  
             * Right now it just grabs 'count' amount 
             * of characters from the beginning of the
             * LipsumText.  It'd be nice if it could 
             * generate sentences and then truncate them 
             * but I can't think of an elegant way to 
             * do that at the moment.  TODO. */

            if (count >= LipsumText.Length)
            {
                count = LipsumText.Length - 1;
            }
            char[] chars = LipsumText.ToString().ToCharArray(0, count);

            result[0] = new String(chars);

            return result;
        }

        private static string[] GenerateParagraphs(int count)
        {
            return GenerateParagraphs(count, "");
        }

        private static string[] GenerateParagraphs(int count, string formatString)
        {
            Paragraph options = Paragraph.Medium;
            options.FormatString = formatString;
            return GenerateParagraphs(count, options);
        }

        private static string[] GenerateParagraphs(int count, Paragraph options)
        {
            /*
             * TODO:  These generate methods could probably be 
             * refactored into one method that takes a count 
             * and a TextFeature. */
            string[] paragraphs = new string[count];
            string[] sentences = new string[] { };
            for (int i = 0; i < count; i++)
            {
                /* Get a random amount of sentences based on the
                 * min and max from the paragraph options */
                sentences = GenerateSentences(LipsumUtilities.
                    RandomInt((int)options.GetMinimum(), (int)options.GetMaximum()));

                // Shove them all together in sentence fashion.
                string joined = String.Join(options.Delimiter, sentences);

                // Format if allowed.
                paragraphs[i] = String.IsNullOrEmpty(options.FormatString) ?
                    joined : options.Format(joined);
            }

            return paragraphs;
        }

        private static string[] GenerateSentences(int count)
        {
            return GenerateSentences(count, FormatStrings.Sentence.Phrase);
        }

        private static string[] GenerateSentences(int count, string formatString)
        {
            Sentence options = Sentence.Medium;
            options.FormatString = formatString;
            return GenerateSentences(count, options);
        }

        private static string[] GenerateSentences(int count, Sentence options)
        {
            string[] sentences = new string[count];
            string[] words = new string[] { };

            for (int i = 0; i < count; i++)
            {
                /* Get a random amount of words based on the
                 * min and max from the Sentence options */
                words = GenerateWords(LipsumUtilities.
                    RandomInt((int)options.MinimumWords, (int)options.MaximumWords));

                // Shove them all together in sentence fashion.
                string joined = String.Join(options.Delimiter, words);

                // Format if allowed.
                sentences[i] = String.IsNullOrEmpty(options.FormatString) ?
                    joined : options.Format(joined);
            }

            return sentences;
        }

        private static string[] GenerateWords(int count)
        {
            string[] words = new string[count];

            for (int i = 0; i < count; i++)
            {
                words[i] = LipsumUtilities.RandomElement(PreparedWords);
            }

            return words;
        }


        private static string[] PrepareWords()
        {
            return LipsumUtilities.RemoveEmptyElements(
                Regex.Split(LipsumText.ToString(), @"\s"));
        }

        private static StringBuilder LipsumText
        {
            get
            {
                if (_lipsumText == null || string.IsNullOrWhiteSpace(_lipsumText.ToString()))
                {
                    _lipsumText = LipsumUtilities.GetTextFromRawXml(LipsumDefaultText);
                }
                return _lipsumText;
            }
            set
            {
                _lipsumText = value;
                PreparedWords = PrepareWords();
            }
        }

        private static string[] PreparedWords
        {
            get { return _preparedWords; }
            set { _preparedWords = value; }
        }
    }
}
